﻿using System;
using System.Data;
using System.Data.OleDb;
using System.Text;
using CarolLib.Helper;

namespace HQDBF
{
    /// <summary>
    /// 行情查询类
    /// </summary>
    public class PriceQuery
    {
        private static readonly string CON_HS300ZJCJ = "SELECT HQZJCJ AS Price FROM SJSHQ WHERE HQZQDM = '399300'";

        private string connSH;
        private string connSZ;

        #region ctor.

        /// <summary>
        /// 创建PriceQuery对象, DBF文件默认地址从.config文件读取
        /// </summary>
        public PriceQuery()
        {
            connSH = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", System.Configuration.ConfigurationSettings.AppSettings["Show2003Path"]);
            connSZ = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", System.Configuration.ConfigurationSettings.AppSettings["SJSHQPath"]);
        }

        /// <summary>
        /// 创建PriceQuery对象
        /// </summary>
        /// <param name="Path">两个DBF文件所在的地址</param>
        public PriceQuery(string Path)
        {
            connSH = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", Path);
            connSZ = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", Path);
        }

        /// <summary>
        /// 创建PriceQuery对象
        /// </summary>
        /// <param name="Path">两个DBF文件所在的地址</param>
        public PriceQuery(string Show2003Path, string SJSHQPath)
        {
            connSH = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", Show2003Path);
            connSZ = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=dBASE IV;", SJSHQPath);
        }

        #endregion

        #region API

        /// <summary>
        /// 获取单只股票的买入价
        /// </summary>
        /// <param name="code">股票代码</param>
        /// <param name="x">买x</param>
        /// <returns>买入价x</returns>
        public double GetBuyPriceX(string code, int x)
        {
            return GetPriceX(code, true, x);
        }

        /// <summary>
        /// 获取单只股票的卖出价
        /// </summary>
        /// <param name="code"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public double GetSellPriceX(string code, int x)
        {
            return GetPriceX(code, false, x);
        }

        /// <summary>
        /// 获取多个买入价x
        /// </summary>
        /// <param name="codes">股票代码数组</param>
        /// <param name="x">买家x</param>
        /// <returns>结果按代码升序</returns>
        public double[] GetBuyPricesX(string[] codes, int x)
        {
            return GetPricesX(codes, true, x);
        }

        /// <summary>
        /// 获取多个卖出价x
        /// </summary>
        /// <param name="codes">股票代码数组</param>
        /// <param name="x">卖价x</param>
        /// <returns>结果按代码升序</returns>
        public double[] GetSellPricesX(string[] codes, int x)
        {
            return GetPricesX(codes, false, x);
        }

        /// <summary>
        /// 获取沪深300最近成交价
        /// </summary>
        /// <returns></returns>
        public double GetHS300ZJCJ()
        {
            double result = 0;

            OleDbDataReader reader = OleDbHelper.ExecuteReader(connSZ, CommandType.Text, CON_HS300ZJCJ);

            if (reader.Read())
            {
                result = reader.GetDouble(0);
            }

            reader.Close();
            reader.Dispose();

            return result;
        }

        /// <summary>
        /// 获取单只股票的买入价及其对应的股数
        /// </summary>
        /// <param name="code">股票代码</param>
        /// <param name="x">买x</param>
        /// <returns>买x对应的申报价记录</returns>
        public PriceRecord GetBuyPriceXWithAmount(string code, int x)
        {
            return GetPriceXWithAmount(code, true, x);
        }

        /// <summary>
        /// 获取单只股票的卖出价及其对应的股数
        /// </summary>
        /// <param name="code">股票代码</param>
        /// <param name="x">卖x</param>
        /// <returns>卖x对应的申报价记录</returns>
        public PriceRecord GetSellPriceXWithAmount(string code, int x)
        {
            return GetPriceXWithAmount(code, false, x);
        }

        /// <summary>
        /// 获取多个买入价x及其对应的股数
        /// </summary>
        /// <param name="codes">股票代码数组</param>
        /// <param name="x">买x</param>
        /// <returns>买x对应的申报价记录集合，结果按代码升序</returns>
        public PriceRecord[] GetBuyPricesXWithAmount(string[] codes, int x)
        {
            return GetPricesXWithAmount(codes, true, x);
        }

        /// <summary>
        /// 获取多个卖出价x及其对应的股数
        /// </summary>
        /// <param name="codes">股票代码数组</param>
        /// <param name="x">卖x</param>
        /// <returns>卖x对应的申报价记录集合，结果按代码升序</returns>
        public PriceRecord[] GetSellPricesXWithAmount(string[] codes, int x)
        {
            return GetPricesXWithAmount(codes, false, x);
        }

        #endregion

        #region Privates

        private string GetField(bool isSH, bool isBuy, int x)
        {
            #region Shanghai

            if (isSH)
            {
                //S9当前买入价、S10当前卖出价、S16申买价二、S18申买价三、
                //S22申卖价二、S24申卖价三、S26申买价四、S28申买价五、S30申卖价四、S32申卖价五

                if (isBuy)
                {
                    switch (x)
                    {
                        case 1:
                            return "S9";
                        case 2:
                            return "S16";
                        case 3:
                            return "S18";
                        case 4:
                            return "S26";
                        case 5:
                            return "S28";
                        default:
                            return "S9";
                    }
                }
                else
                {
                    switch (x)
                    {
                        case 1:
                            return "S10";
                        case 2:
                            return "S22";
                        case 3:
                            return "S24";
                        case 4:
                            return "S30";
                        case 5:
                            return "S32";
                        default:
                            return "S10";
                    }
                }
            }

            #endregion
            #region Shenzhen

            else
            {
                if (isBuy)
                {
                    return "HQBJW" + x.ToString();
                }
                else
                {
                    return "HQSJW" + x.ToString();
                }
            }

            #endregion
        }

        private string GetAmount(bool isSH, bool isBuy, int x)
        {
            #region Shanghai

            if (isSH)
            {
                //S15申买量一、S17申买量二、S19申买量三、S27申买量四、S29申买量五
                //S21申卖量一、S23申卖量二、S25申卖量三、S31申卖量四、S33申卖量五

                if (isBuy)
                {
                    switch (x)
                    {
                        case 1:
                            return "S15";
                        case 2:
                            return "S17";
                        case 3:
                            return "S19";
                        case 4:
                            return "S27";
                        case 5:
                            return "S29";
                        default:
                            return "S15";
                    }
                }
                else
                {
                    switch (x)
                    {
                        case 1:
                            return "S21";
                        case 2:
                            return "S23";
                        case 3:
                            return "S25";
                        case 4:
                            return "S31";
                        case 5:
                            return "S33";
                        default:
                            return "S21";
                    }
                }
            }

            #endregion
            #region Shenzhen

            else
            {
                if (isBuy)
                {
                    return "HQBSL" + x.ToString();
                }
                else
                {
                    return "HQSSL" + x.ToString();
                }
            }

            #endregion
        }

        private double GetPriceX(string code, bool isBuy, int x)
        {
            OleDbDataReader reader;
            int icode = Convert.ToInt32(code);
            if (icode < 600000)
            {
                string sbSZ = string.Format(
                    "SELECT HQZQDM AS Code, {0} AS Price FROM SJSHQ WHERE HQZQDM='{1}'",
                    GetField(false, isBuy, x), code);
                reader = OleDbHelper.ExecuteReader(this.connSZ, CommandType.Text, sbSZ);
            }
            else
            {
                string sbSH = string.Format(
                    "SELECT S1 AS Code, {0} AS Price FROM SHOW2003 WHERE S1='{1}'",
                    GetField(true, isBuy, x), code);
                reader = OleDbHelper.ExecuteReader(this.connSH, CommandType.Text, sbSH);
            }

            if (reader.Read())
            {
                double result = reader.GetDouble(1);
                reader.Close();
                return result;
            }
            else
            {
                throw new Exception("未能找到数据");
            }
        }

        private double[] GetPricesX(string[] codes, bool isBuy, int x)
        {
            double[] result = new double[codes.Length];

            StringBuilder sbSH = new StringBuilder(
                string.Format("SELECT S1 AS Code, {0} AS Price FROM SHOW2003 WHERE S1 BETWEEN '600000' AND '610000'",
                GetField(true, isBuy, x), x));
            StringBuilder sbSZ = new StringBuilder(
                string.Format("SELECT HQZQDM AS Code, {0} AS Price FROM SJSHQ WHERE HQZQDM BETWEEN '000000' AND '100000'",
                GetField(false, isBuy, x), x));

            DataTable dtSH = OleDbHelper.ExecuteDataset(connSH, CommandType.Text, sbSH.ToString()).Tables[0];
            DataTable dtSZ = OleDbHelper.ExecuteDataset(connSZ, CommandType.Text, sbSZ.ToString()).Tables[0];

            foreach (DataRow row in dtSZ.Rows)
            {
                dtSH.ImportRow(row);
            }

            DataRow[] rows;
            for (int i = 0; i < codes.Length; i++)
            {
                rows = dtSH.Select("Code='" + codes[i] + "'");
                if (rows.Length > 0)
                {
                    result[i] = Convert.ToDouble(rows[0]["Price"].ToString());
                }
                else
                {
                    result[i] = 0;
                }
            }

            return result;
        }

        private PriceRecord GetPriceXWithAmount(string code, bool isBuy, int x)
        {
            PriceRecord result = new PriceRecord();
            OleDbDataReader reader;
            int icode = Convert.ToInt32(code);
            if (icode < 600000)
            {
                string sbSZ = string.Format(
                    "SELECT HQZQDM AS Code, {0} AS Price, {1} as Amount FROM SJSHQ WHERE HQZQDM='{1}'",
                    GetField(false, isBuy, x), GetAmount(false, isBuy, x), code);
                reader = OleDbHelper.ExecuteReader(this.connSZ, CommandType.Text, sbSZ);
            }
            else
            {
                string sbSH = string.Format(
                    "SELECT S1 AS Code, {0} AS Price, {1} as Amount FROM SHOW2003 WHERE S1='{1}'",
                    GetField(true, isBuy, x), GetAmount(false, isBuy, x), code);
                reader = OleDbHelper.ExecuteReader(this.connSH, CommandType.Text, sbSH);
            }

            if (reader.Read())
            {
                result.Code = code;
                result.Price = reader.GetDouble(1);
                result.Amount = reader.GetInt32(2);
                reader.Close();
                return result;
            }
            else
            {
                throw new Exception("未能找到数据");
            }
        }

        private PriceRecord[] GetPricesXWithAmount(string[] codes, bool isBuy, int x)
        {
            PriceRecord[] result = new PriceRecord[codes.Length];

            StringBuilder sbSH = new StringBuilder(
                string.Format("SELECT S1 AS Code, {0} AS Price, {1} as Amount FROM SHOW2003 WHERE S1 BETWEEN '600000' AND '610000'",
                GetField(true, isBuy, x), GetAmount(true, isBuy, x), x));
            StringBuilder sbSZ = new StringBuilder(
                string.Format("SELECT HQZQDM AS Code, {0} AS Price, {1} as Amount FROM SJSHQ WHERE HQZQDM BETWEEN '000000' AND '100000'",
                GetField(false, isBuy, x), GetAmount(false, isBuy, x), x));

            DataTable dtSH = OleDbHelper.ExecuteDataset(connSH, CommandType.Text, sbSH.ToString()).Tables[0];
            DataTable dtSZ = OleDbHelper.ExecuteDataset(connSZ, CommandType.Text, sbSZ.ToString()).Tables[0];

            foreach (DataRow row in dtSZ.Rows)
            {
                dtSH.ImportRow(row);
            }

            DataRow[] rows;
            for (int i = 0; i < codes.Length; i++)
            {
                rows = dtSH.Select("Code='" + codes[i] + "'");

                result[i] = new PriceRecord();
                result[i].Code = codes[i];

                if (rows.Length > 0)
                {
                    result[i].Price = Convert.ToDouble(rows[0]["Price"].ToString());
                    result[i].Amount = Convert.ToInt32(rows[0]["Amount"].ToString());
                }
                else
                {
                    result[i].Price = 0;
                    result[i].Amount = 0;
                }
            }

            return result;
        }

        #endregion
    }

    /// <summary>
    /// 申报价记录
    /// <example>如：{Code:600570,Price:12.52,Amount:23100} </example>
    /// </summary>
    public class PriceRecord
    {
        private string code;
        /// <summary>
        /// 股票代码
        /// </summary>
        public string Code
        {
            get { return code; }
            set { code = value; }
        }

        private double price;
        /// <summary>
        /// 申报价格
        /// </summary>
        public double Price
        {
            get { return price; }
            set { price = value; }
        }

        private int amount;
        /// <summary>
        /// 价格对应的数量
        /// </summary>
        public int Amount
        {
            get { return amount; }
            set { amount = value; }
        }
    }
}
